from pathlib import Path
import pandas as pd
from datetime import datetime
import os
import numpy as np


class AppConfigConstant:
    """
    app配置常量
    """
    INTERVAL_LIST = [1, 3, 7, 15, 30, 60, 90, 180, 360, 'all']
    TIME_PERIODS = [(0, 5, 'early_morning'), (6, 10, 'morning'), (11, 13, 'noon'), (14, 17, 'afternoon'),
                    (18, 23, 'night')]
    # WEEK_TYPES = ['weekday', 'weekend']


class AppOverdueRateV1:
    """
    app逾期率特征
    """
    @staticmethod
    def extract_app_rlevel_cnt_features(
            df: pd.DataFrame,
            time_col: str,
            config_all: pd.DataFrame,
            apply_time: str
    ):
        """
        提取app_rlevel_cnt特征
        Args:
            df: 数据
            time_col: 时间列
            config_all: app配置数据
            apply_time: 申请时间
        Returns:
            app_rlevel_cnt特征
        """
        feature_dict = {}
        apply_time = pd.to_datetime(apply_time)
        for risk_level in config_all['risk_level'].unique():
            apps = set(config_all[config_all['risk_level'] == risk_level]['app'])
            for time_window in AppConfigConstant.INTERVAL_LIST:
                if time_window == 'all':
                    time_data = df[df[time_col] <= apply_time]
                else:
                    time_window_ = pd.Timedelta(days=time_window)
                    time_data = df[(df[time_col] >= apply_time - time_window_) & (df[time_col] <= apply_time)]
                # app_count = time_data[time_data['app_package'].isin(apps)].shape[0]
                app_count = len(set(time_data[time_data['app_name'].isin(apps)]['app_name']))
                feature_dict[f'app_cnt_rlevel{risk_level}_d{time_window}'] = app_count
                if len(time_data) == 0:
                    feature_dict[f'app_ratio_rlevel{risk_level}_d{time_window}'] = 0
                else:
                    feature_dict[f'app_ratio_rlevel{risk_level}_d{time_window}'] = app_count / len(time_data)
                # feature_dict 按key排序
                feature_dict = dict(sorted(feature_dict.items(), key=lambda x: x[0]))
        return feature_dict

    @staticmethod
    def extract_app_rlevel_time_features(
            df: pd.DataFrame,
            time_col: str,
            config_all: pd.DataFrame,
            apply_time: str
    ):
        """
        提取app_rlevel_time特征
        Args:
            df: 数据
            time_col: 时间列, fi_time / lu_time
            config_all: app配置数据
            apply_time: 申请时间
        Returns:
            app_rlevel_time特征
        """
        feature_dict = {}
        apply_time = pd.to_datetime(apply_time)
        for risk_level in config_all['risk_level'].unique():
            apps = set(config_all[config_all['risk_level'] == risk_level]['app'])
            feature_dict[f'app_time_diff_rlevel{risk_level}_max'] = (
                    apply_time - df[df['app_name'].isin(apps)][time_col]).max().days
            feature_dict[f'app_time_diff_rlevel{risk_level}_min'] = (
                    apply_time - df[df['app_name'].isin(apps)][time_col]).min().days
            feature_dict[f'app_time_diff_rlevel{risk_level}_mean'] = (
                    apply_time - df[df['app_name'].isin(apps)][time_col]).mean().days
            feature_dict[f'app_time_diff_rlevel{risk_level}_std'] = (
                    apply_time - df[df['app_name'].isin(apps)][time_col]).std().days
            feature_dict = dict(sorted(feature_dict.items(), key=lambda x: x[0]))
        return feature_dict

    @staticmethod
    def extract_app_rlevel_continuous_day_features(
            df: pd.DataFrame,
            time_col: str,
            config_all: pd.DataFrame,
            apply_time: str
    ):
        """
        提取app_rlevel_continunous_day特征
        Args:
            df: 数据
            time_col: 时间列
            config_all: app配置数据
            apply_time: 申请时间
        Returns:
            app_rlevel_continunous_day特征
        """
        feature_dict = {}
        apply_time = pd.to_datetime(apply_time)
        for risk_level in config_all['risk_level'].unique():
            apps = set(config_all[config_all['risk_level'] == risk_level]['app'])
            for time_window in AppConfigConstant.INTERVAL_LIST:
                if time_window == 'all':
                    time_data = df[df[time_col] <= apply_time]
                else:
                    time_window_ = pd.Timedelta(days=time_window)
                    time_data = df[(df[time_col] >= apply_time - time_window_) & (df[time_col] <= apply_time)]
                time_data = time_data.sort_values(by='fi_day', ascending=False)
                time_data.reset_index(drop=True, inplace=True)
                time_day_list = time_data[time_data['app_name'].isin(apps)]['fi_day'].unique()
                if len(time_day_list) == 0:
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_max'] = 0
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_min'] = 0
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_mean'] = 0
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_std'] = 0
                elif len(time_day_list) == 1:
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_max'] = 1
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_min'] = 1
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_mean'] = 1
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_std'] = 0
                else:
                    continunous_day = 1
                    continunous_day_list = []
                    for i in range(1, len(time_day_list)):
                        if (time_day_list[i - 1] - time_day_list[i]).days == 1:
                            continunous_day += 1
                        else:
                            continunous_day_list.append(continunous_day)
                            continunous_day = 1
                    continunous_day_list.append(continunous_day)
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_max'] = max(continunous_day_list)
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_min'] = min(continunous_day_list)
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_mean'] = np.mean(
                        continunous_day_list)
                    feature_dict[f'app_continunous_rlevel{risk_level}_d{time_window}_std'] = np.std(
                        continunous_day_list)
            feature_dict = dict(sorted(feature_dict.items(), key=lambda x: x[0]))
        return feature_dict

    @staticmethod
    def extract_app_rlevel_shift_diff_features(
            df: pd.DataFrame,
            time_col: str,
            config_all: pd.DataFrame,
            apply_time: str
    ):
        """
        提取app_rlevel_shift_diff特征
        Args:
            df: 数据
            time_col: 时间列
            config_all: app配置数据
            apply_time: 申请时间
        Returns:
            app_rlevel_shift_diff特征
        """
        feature_dict = {}
        apply_time = pd.to_datetime(apply_time)
        for risk_level in config_all['risk_level'].unique():
            apps = set(config_all[config_all['risk_level'] == risk_level]['app'])
            for time_window in AppConfigConstant.INTERVAL_LIST:
                if time_window == 'all':
                    continue
                else:
                    time_window_ = pd.Timedelta(days=time_window)
                    time_data = df[(df[time_col] >= apply_time - 2 * time_window_) & (df[time_col] <= apply_time)]
                now_window_num = len(set(time_data[time_data[time_col] > apply_time - time_window_]['app_name']) & apps)
                last_window_num = len(set(
                    time_data[time_data[time_col].between(apply_time - 2 * time_window_, apply_time - time_window_)][
                        'app_name']) & apps)
                feature_dict[f'app_shift_diff_rlevel{risk_level}_d{time_window}'] = now_window_num - last_window_num
                if last_window_num == 0:
                    feature_dict[f'app_shift_diff_ratio_rlevel{risk_level}_d{time_window}'] = -99
                else:
                    feature_dict[f'app_shift_diff_ratio_rlevel{risk_level}_d{time_window}'] = (now_window_num - last_window_num) / last_window_num
            feature_dict = dict(sorted(feature_dict.items(), key=lambda x: x[0]))
        return feature_dict

    @staticmethod
    def extract_app_rlevel_time_period_features(
            df: pd.DataFrame,
            time_col: str,
            config_all: pd.DataFrame,
            apply_time: str
    ):
        """
        提取app_rlevel_time_period特征
        Args:
            df: 数据
            time_col: 时间列
            config_all: app配置数据
            apply_time: 申请时间
        Returns:
            app_rlevel_time_period特征
        """
        feature_dict = {}
        apply_time = pd.to_datetime(apply_time)
        for risk_level in config_all['risk_level'].unique():
            apps = set(config_all[config_all['risk_level'] == risk_level]['app'])
            for time_window in AppConfigConstant.INTERVAL_LIST:
                if time_window == 'all':
                    time_data = df[df[time_col] <= apply_time]
                else:
                    time_window_ = pd.Timedelta(days=time_window)
                    time_data = df[(df[time_col] >= apply_time - time_window_) & (df[time_col] <= apply_time)]
                for time_period in AppConfigConstant.TIME_PERIODS:
                    time_data_period = time_data[(time_data['fi_hour'].between(time_period[0], time_period[1]))]
                    feature_dict[f'app_cnt_rlevel{risk_level}_{time_period[2]}_d{time_window}'] = len(
                        set(time_data_period['app_name']) & apps)
                    if len(time_data_period) == 0:
                        feature_dict[f'app_ratio_rlevel{risk_level}_{time_period[2]}_d{time_window}'] = -99
                    else:
                        feature_dict[f'app_ratio_rlevel{risk_level}_{time_period[2]}_d{time_window}'] = len(
                            set(time_data_period['app_name']) & apps) / len(time_data_period)

            feature_dict = dict(sorted(feature_dict.items(), key=lambda x: x[0]))
        return feature_dict
